package baseFx.springboot.components;

import baseFx.common.AutoCloseable;
import baseFx.common.lock.Lockspace;
import baseFx.common.lock.LockspaceException;
import baseFx.springboot.ActionEventArgs;
import baseFx.springboot.FxController;
import baseFx.springboot.MvcEvents;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

/**
 * 基于RequestUser来保证一个用户只存在一个Post请求
 */
public class PostIdempotent {
    private static String key = UUID.randomUUID().toString();
    private Lockspace lockspace;

    public PostIdempotent(MvcEvents mvcEvents, Lockspace lockspace) {
        this.lockspace = lockspace;
        mvcEvents.actionBefore.add((t, e) -> begin(e));
        mvcEvents.requestAfter.add((t, e) -> unlock(e.request));
    }

    private void begin(ActionEventArgs args) {
        if ("post".equalsIgnoreCase(args.request.getMethod()) == false) {
            return;
        }
        if (FxController.class.isInstance(args.handler) == false) {
            return;
        }
        FxController ctrl = (FxController) args.handler;
        if (ctrl.currentUser() == null) {
            return;
        }
        String uid = ctrl.currentUser().getId();
        AutoCloseable ac = lock(uid);
        if (ac == null) {
            args.result = lockFail(uid);
        } else {
            args.request.setAttribute(key, ac);
        }
    }

    protected Object lockFail(String uid) {
        return "POST并发，请稍后重试";
    }

    protected String lockKey(String uid) {
        return uid + ".PostIdempotent";
    }

    protected AutoCloseable lock(String uid) {
        try {
            return lockspace.exLock(lockKey(uid));
        } catch (LockspaceException e) {
            return null;
        }
    }

    protected void unlock(HttpServletRequest request) {
        Object value = request.getAttribute(key);
        if (value instanceof AutoCloseable) {
            ((AutoCloseable) value).close();
        }
    }
}
